/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#include "Transaction.h"
#include "Utilities.h"
#include "StockDatabase.h"

namespace QSThink
{

	TransactionSingle::TransactionSingle()
		:  flag(0),time(0),price(0),volume(0),amount(0)
	{

	}

	TransactionSingle::TransactionSingle( int t,int p,int v,int a,int f )
		:  flag(f),time(t),price(p),volume(v),amount(a)
	{

	}

	Transaction1Day::Transaction1Day(QString symbol,int day)
		: _day(day),_symbol(symbol),_highPrice(0),_lowPrice(0),
		_volume(0),_amount(0),_openPrice(0),_closePrice(0),
		_highIndex(0),_lowIndex(0),_valid(false),_statisticed(false)
	{

		/*
		QString dateStr=Utilities::getDateStrByDay(_day);

		QString fileName=_symbol+"/"+dateStr+".trans";
		QFile file(fileName);

		if (!file.open(QFile::ReadOnly)){
			return;
		}

		_hasData=true;

		QByteArray bytes=file.readAll();

		initTransactions(bytes);

		*/
	}
	
	TransactionSingle* Transaction1Day::parseLine(QString line )
	{
		QStringList lines =line.split("\t");
		int cnt=lines.count();
		if(cnt!=6){
			return 0;
			//QList<QString> = [6]("14:59:45","3.29","--","349","114821","B/S")

		}

		int time=Utilities::getSecondsFrom9(lines[0]);
		float price=lines[1].toFloat();

		float price100=price*100.0f;//unit is feng
		int volume=lines[3].toInt();
		int amount=lines[4].toInt();

		int type=Utilities::getTransType(lines[5]);

		TransactionSingle* trans=new TransactionSingle(time,price100,volume,amount,type);
		return trans;
	}

	bool Transaction1Day::fillData( QByteArray bytes )
	{
		QDir dir;
		if(!dir.exists(_symbol)){
			if(!dir.mkdir(_symbol)){
				return false;
			}
		}
		

		if(initTransactionsByText(bytes)){
			persit();
		}else{
			return false;

		}

		return true;
		

	}

	bool Transaction1Day::initTransactionsByText( QByteArray bytes )
	{
		QString text=QTextCodec::codecForName("GB2312")->toUnicode(bytes);
		if(text.startsWith("<script")){
			return true;
		}
		QStringList lines =text.split("\n");


		int cntLine=lines.count();

		int index=0;
		//check last line that not null
		for(index=cntLine-1;index>0;index--){
			QStringList words =lines[index].split("\t");
			int cnt=words.count();

			if(words[0]!=""){
				if(cnt!=6){
					_valid=false;
					return false;
				}else{
					QTime time=Utilities::getTimeByStr(words[0]);
					int hour=time.hour();
					int minute=time.minute();
					if(hour==9&&minute<=30){
						_valid=true;
						break;
					}else{
						_valid=false;
						return false;
					}
				}
			}
		}


		//start from 1 because 0 is meta info we don't need
		for(int i=1;i<cntLine;i++){
			QString line=lines[i];
			TransactionSingle* trans=parseLine(line);//sorted
			if(trans){
				_transactions.push_back(trans);
			}
		}


		calcDayInfo();
		return true;

	}

	void Transaction1Day::persit()
	{
		int cnt=_transactions.size();

		if(cnt==0){
			return;//no data
		}

		QString dateStr=Utilities::getDateStrByDay(_day);
		QString fileName=_symbol+"/"+dateStr+".trans";
		QFile file(fileName);
		if (!file.open(QFile::WriteOnly)){
			return;
		}

		QByteArray bytes;
		bytes.append((char*)&cnt,sizeof(cnt));
		for(int i=0;i<cnt;++i){
			bytes.append((char*)&_transactions[i]->flag,sizeof(_transactions[i]->flag));
			bytes.append((char*)&_transactions[i]->time,sizeof(_transactions[i]->time));
			bytes.append((char*)&_transactions[i]->price,sizeof(_transactions[i]->price));
			bytes.append((char*)&_transactions[i]->volume,sizeof(_transactions[i]->volume));
			bytes.append((char*)&_transactions[i]->amount,sizeof(_transactions[i]->amount));
		}

		file.write(bytes);

	}

	bool Transaction1Day::loadData()
	{
		int cnt=_transactions.size();

		if(cnt>0){
			return true;//have data
		}

		QString dateStr=Utilities::getDateStrByDay(_day);
		QString fileName=_symbol+"/"+dateStr+".trans";
		QFile file(fileName);
		if (!file.open(QFile::ReadOnly)){
			return false;
		}
		
		QByteArray bytes=file.readAll();
		char* data=bytes.data();
		int index=0;

		cnt=*(int*)(data+index);
		index+=sizeof(cnt);

		for(int i=0;i<cnt;++i){
			
			int flag=*(int*)(data+index);
			index+=sizeof(flag);

			int time=*(int*)(data+index);
			index+=sizeof(time);

			int price=*(int*)(data+index);
			index+=sizeof(price);

			int volume=*(int*)(data+index);
			index+=sizeof(volume);

			int amount=*(int*)(data+index);
			index+=sizeof(amount);

			TransactionSingle* trans=new TransactionSingle(time,price,volume,amount,flag);
			_transactions.push_back(trans);

		}
		
		calcDayInfo();
		calc2MinutesTrans();

		
		return true;
	}

	void Transaction1Day::calcDayInfo()
	{
		int cnt=_transactions.size();
		float total=0;
		for (int i=0;i<cnt;++i){
			if(i==0){
				_highIndex=0;
				_lowIndex=0;
				_highPrice=_transactions[i]->price;
				_lowPrice=_transactions[i]->price;
				_closePrice=_transactions[i]->price;
			}else{
				if(_highPrice<_transactions[i]->price){
					_highPrice=_transactions[i]->price;
					_highIndex=i;
				}

				if(_lowPrice>_transactions[i]->price){
					_lowPrice=_transactions[i]->price;
					_lowIndex=i;
				}

			}

			if(i==cnt-1){
				_openPrice=_transactions[i]->price;
			}

			total+=_transactions[i]->price;
		}

		_balancePrice=total/(float)cnt;

		

	}

	void Transaction1Day::calc2MinutesTrans()
	{
		int cnt=_transactions.size();
		float total=0;
		for (int i=0;i<cnt;++i){
			TransactionSingle* trans=_transactions[i];
			int time=trans->time;
			int index=Utilities::get2MinutesOffset(time);
			assert(index>=0&&index<120);

			_2minutesTrans[index].setIndex(index);
			_2minutesTrans[index].addTrans(trans);

		}
	}

	

	void Transaction1Day::setStatistics( float balancePrice, int openPrice, int closePrice, int highPrice, int highIndex, int lowPrice, int lowIndex, int volume, int amount )
	{
		_balancePrice=balancePrice;
		_openPrice=openPrice;
		_closePrice=closePrice;
		_highPrice=highPrice;
		_highIndex=highIndex;
		_lowPrice=lowPrice;
		_lowIndex=lowIndex;
		_amount=amount;
		_volume=volume;

		_statisticed=true;
	}

	float Transaction1Day::balancePriceEx()
	{
		double power=StockDatabase::getSingleton().getStockPower(_symbol,_day);
		return _balancePrice*power;


	}

	float Transaction1Day::highPriceEx()
	{
		double power=StockDatabase::getSingleton().getStockPower(_symbol,_day);
		return _highPrice*power;

	}

	float Transaction1Day::lowPriceEx()
	{
		double power=StockDatabase::getSingleton().getStockPower(_symbol,_day);
		return _lowPrice*power;

	}

	

}
